package com.ovm.uy.persistence;

import java.util.List;

import javax.persistence.EntityExistsException;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

import com.ovm.uy.persistence.criterial.Criterial;
import com.ovm.uy.persistence.exceptions.DAOEntityExist;
import com.ovm.uy.persistence.exceptions.DAOException;

public abstract class AbstractDAO<T> {
	private Class<T> entityClass;

	public AbstractDAO(Class<T> entityClass) {
		this.entityClass = entityClass;

	}

	@PersistenceContext
	public abstract EntityManager getEntityManager();

	public void create(T entity) throws DAOEntityExist {
		try {
			getEntityManager().persist(entity);
		} catch (EntityExistsException e) {
			throw new DAOEntityExist("Entity Exists", e);
		}
	}

	public void edit(T entity) throws DAOException {
		try {
			getEntityManager().merge(entity);
		} catch (IllegalArgumentException e) {
			throw new DAOException(
					"Instance is not an entity or is a removed entity ", e);
		}
	}

	public void remove(T entity) throws DAOException {
		try {
			getEntityManager().remove(getEntityManager().merge(entity));
		} catch (IllegalArgumentException e) {
			throw new DAOException(
					"Instance is not an entity or is a removed entity ", e);
		}
	}

	public void flush() {
		getEntityManager().flush();
	}

	public T find(Object id) {
		return getEntityManager().find(entityClass, id);
	}

	@SuppressWarnings("unchecked")
	public List<T> findAll() {
		String sQuery;
		sQuery = "SELECT C FROM " + entityClass.getSimpleName() + " C";
		return getEntityManager().createQuery(sQuery).getResultList();
	}

	@SuppressWarnings("unchecked")
	public List<T> findRange(int[] range) {
		String sQuery;
		sQuery = "SELECT C FROM " + entityClass.getSimpleName() + " C";
		javax.persistence.Query q = getEntityManager().createQuery(sQuery);
		q.setMaxResults(range[1] - range[0]);
		q.setFirstResult(range[0]);
		return q.getResultList();
	}

	@SuppressWarnings({ "unchecked", "rawtypes" })
	public int count() {
		javax.persistence.criteria.CriteriaQuery cq = getEntityManager()
				.getCriteriaBuilder().createQuery();
		javax.persistence.criteria.Root<T> rt = cq.from(entityClass);
		cq.select(getEntityManager().getCriteriaBuilder().count(rt));
		javax.persistence.Query q = getEntityManager().createQuery(cq);
		return ((Long) q.getSingleResult()).intValue();
	}

	@SuppressWarnings("unchecked")
	public List<T> findCriterial(Criterial oCriterial) {
		Query oQuery;
		oQuery = getEntityManager()
				.createNamedQuery(oCriterial.getSearchName());
		if (oCriterial.getParams() != null) {
			for (String sParamName : oCriterial.getParams().keySet()) {
				oQuery.setParameter(sParamName,
						oCriterial.getParams().get(sParamName));
			}
		}
		return oQuery.getResultList();
	}
}